home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / elv18src.zip / move1.c < prev    next >
C/C++ Source or Header  |  1994-01-21  |  12KB  |  646 lines

  1. /* move1.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains most movement functions */
  12.  
  13. #include "config.h"
  14. #include "vi.h"
  15. #include "ctype.h"
  16.  
  17. MARK    m_updnto(m, cnt, cmd)
  18.     MARK    m;    /* movement is relative to this mark */
  19.     long    cnt;    /* a numeric argument */
  20.     int    cmd;    /* the command character */
  21. {
  22.     DEFAULT(cmd == 'G' ? nlines : 1L);
  23.  
  24.     /* move up or down 'cnt' lines */
  25.     switch (cmd)
  26.     {
  27.       case ctrl('P'):
  28.       case '-':
  29.       case 'k':
  30.         m -= MARK_AT_LINE(cnt);
  31.         break;
  32.  
  33.       case 'G':
  34.         if (cnt < 1L || cnt > nlines)
  35.         {
  36.             msg("Only %ld lines", nlines);
  37.             return MARK_UNSET;
  38.         }
  39.         m = MARK_AT_LINE(cnt);
  40.         break;
  41.  
  42.       case '_':
  43.         cnt--;
  44.         /* fall through... */
  45.  
  46.       default:
  47.         m += MARK_AT_LINE(cnt);
  48.     }
  49.  
  50.     /* if that left us screwed up, then fail */
  51.     if (m < MARK_FIRST || markline(m) > nlines)
  52.     {
  53.         return MARK_UNSET;
  54.     }
  55.  
  56.     return m;
  57. }
  58.  
  59. /*ARGSUSED*/
  60. MARK    m_right(m, cnt, key, prevkey)
  61.     MARK    m;    /* movement is relative to this mark */
  62.     long    cnt;    /* a numeric argument */
  63.     int    key;    /* movement keystroke */
  64.     int    prevkey;/* operator keystroke, or 0 if none */
  65. {
  66.     int        idx;    /* index of the new cursor position */
  67.  
  68.     DEFAULT(1);
  69.  
  70.     /* If used with an operator, then move 1 less character, since the 'l'
  71.      * command includes the character that it moves onto.
  72.      */
  73.     if (prevkey != '\0')
  74.     {
  75.         cnt--;
  76.     }
  77.  
  78.     /* move to right, if that's OK */
  79.     pfetch(markline(m));
  80.     idx = markidx(m) + cnt;
  81.     if (idx < plen)
  82.     {
  83.         m += cnt;
  84.     }
  85.     else
  86.     {
  87.         return MARK_UNSET;
  88.     }
  89.  
  90.     return m;
  91. }
  92.  
  93. /*ARGSUSED*/
  94. MARK    m_left(m, cnt)
  95.     MARK    m;    /* movement is relative to this mark */
  96.     long    cnt;    /* a numeric argument */
  97. {
  98.     DEFAULT(1);
  99.  
  100.     /* move to the left, if that's OK */
  101.     if (markidx(m) >= cnt)
  102.     {
  103.         m -= cnt;
  104.     }
  105.     else
  106.     {
  107.         return MARK_UNSET;
  108.     }
  109.  
  110.     return m;
  111. }
  112.  
  113. /*ARGSUSED*/
  114. MARK    m_tocol(m, cnt, cmd)
  115.     MARK    m;    /* movement is relative to this mark */
  116.     long    cnt;    /* a numeric argument */
  117.     int    cmd;    /* either ctrl('X') or '|' */
  118. {
  119.     char    *text;    /* text of the line */
  120.     int    col;    /* column number */
  121.     int    idx;    /* index into the line */
  122.  
  123.  
  124.     /* if doing ^X, then adjust for sideways scrolling */
  125.     if (cmd == ctrl('X'))
  126.     {
  127.         DEFAULT(*o_columns & 0xff);
  128.         cnt += leftcol;
  129.     }
  130.     else
  131.     {
  132.         DEFAULT(1);
  133.     }
  134.  
  135.     /* internally, columns are numbered 0..COLS-1, not 1..COLS */
  136.     cnt--;
  137.  
  138.     /* if 0, that's easy */
  139.     if (cnt == 0)
  140.     {
  141.         m &= ~(BLKSIZE - 1);
  142.         return m;
  143.     }
  144.  
  145.     /* find that column within the line */
  146.     pfetch(markline(m));
  147.     text = ptext;
  148.     for (col = idx = 0; col < cnt && *text; text++, idx++)
  149.     {
  150.         if (*text == '\t' && !*o_list)
  151.         {
  152.             col += *o_tabstop;
  153.             col -= col % *o_tabstop;
  154.         }
  155.         else if (UCHAR(*text) < ' ' || *text == '\177')
  156.         {
  157.             col += 2;
  158.         }
  159. #ifndef NO_CHARATTR
  160.         else if (text[0] == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  161.         {
  162.             text += 2; /* plus one more as part of for loop */
  163.         }
  164. #endif
  165.         else
  166.         {
  167.             col++;
  168.         }
  169.     }
  170.     if (!*text)
  171.     {
  172.         /* the desired column was past the end of the line, so
  173.          * act like the user pressed "$" instead.
  174.          */
  175.         return m | (BLKSIZE - 1);
  176.     }
  177.     else
  178.     {
  179.         m = (m & ~(BLKSIZE - 1)) + idx;
  180.     }
  181.     return m;
  182. }
  183.  
  184. /*ARGSUSED*/
  185. MARK    m_front(m, cnt)
  186.     MARK    m;    /* movement is relative to this mark */
  187.     long    cnt;    /* a numeric argument (ignored) */
  188. {
  189.     char    *scan;
  190.  
  191.     /* move to the first non-whitespace character */
  192.     pfetch(markline(m));
  193.     scan = ptext;
  194.     m &= ~(BLKSIZE - 1);
  195.     while (*scan == ' ' || *scan == '\t')
  196.     {
  197.         scan++;
  198.         m++;
  199.     }
  200.  
  201.     return m;
  202. }
  203.  
  204. /*ARGSUSED*/
  205. MARK    m_rear(m, cnt)
  206.     MARK    m;    /* movement is relative to this mark */
  207.     long    cnt;    /* a numeric argument (ignored) */
  208. {
  209.     /* Try to move *EXTREMELY* far to the right.  It is fervently hoped
  210.      * that other code will convert this to a more reasonable MARK before
  211.      * anything tries to actually use it.  (See adjmove() in vi.c)
  212.      */
  213.     return m | (BLKSIZE - 1);
  214. }
  215.  
  216. #ifndef NO_SENTENCE
  217. static int isperiod(ptr)
  218.     char    *ptr;    /* pointer to possible sentence-ender */
  219. {
  220.     /* if not '.', '?', or '!', then it isn't a sentence ender */
  221.     if (*ptr != '.' && *ptr != '?' && *ptr != '!')
  222.     {
  223.         return FALSE;
  224.     }
  225.  
  226.     /* skip any intervening ')', ']', or '"' characters */
  227.     do
  228.     {
  229.         ptr++;
  230.     } while (*ptr == ')' || *ptr == ']' || *ptr == '"');
  231.  
  232.     /* do we have two spaces or EOL? */
  233.     if (!*ptr || ptr[0] == ' ' && ptr[1] == ' ')
  234.     {
  235.         return TRUE;
  236.     }
  237.     return FALSE;
  238. }
  239.  
  240. /*ARGSUSED*/
  241. MARK    m_sentence(m, cnt, cmd)
  242.     MARK    m;    /* movement is relative to this mark */
  243.     long    cnt;    /* a numeric argument */
  244.     int    cmd;    /* either '(' or ')' */
  245. {
  246.     REG char    *text;
  247.     REG long    l;
  248. #ifndef CRUNCH
  249.     /* figure out where the paragraph boundary is */
  250.     MARK        pp = m_paragraph(m, 1L, cmd=='(' ? '{' : '}');
  251. #endif
  252.  
  253.     DEFAULT(1);
  254.  
  255.     /* If '(' command, then move back one word, so that if we hit '(' at
  256.      * the start of a sentence we don't simply stop at the end of the
  257.      * previous sentence and bounce back to the start of this one again.
  258.      */
  259.     if (cmd == '(')
  260.     {
  261.         m = m_bword(m, 1L, 'b');
  262.         if (!m)
  263.         {
  264.             return m;
  265.         }
  266.     }
  267.  
  268.     /* get the current line */
  269.     l = markline(m);
  270.     pfetch(l);
  271.     text = ptext + markidx(m);
  272.  
  273.     /* for each requested sentence... */
  274.     while (cnt-- > 0)
  275.     {
  276.         /* search forward for one of [.?!] followed by spaces or EOL */
  277.         do
  278.         {
  279.             if (cmd == ')')
  280.             {
  281.                 /* move forward, wrap at end of line */
  282.                 if (!text[0])
  283.                 {
  284.                     if (l == nlines)
  285.                     {
  286.                         return(MARK_EOF); /*-g.t.*/
  287.                     }
  288.                     l++;
  289.                     pfetch(l);
  290.                     text = ptext;
  291.                 }
  292.                 else
  293.                 {
  294.                     text++;
  295.                 }
  296.             }
  297.             else
  298.             {
  299.                 /* move backward, wrap at beginning of line */
  300.                 if (text == ptext)
  301.                 {
  302.                     do
  303.                     {
  304.                         if (l == 1L)
  305.                         {
  306.                             return (MARK_FIRST); /*-g.t.*/
  307.                         }
  308.                         l--;
  309.                         pfetch(l);
  310.                     } while (!*ptext);
  311.                     text = ptext + plen - 1;
  312.                 }
  313.                 else
  314.                 {
  315.                     text--;
  316.                 }
  317.             }
  318.         } while (!isperiod(text));
  319.     }
  320. BreakBreak:
  321.  
  322.     /* construct a mark for this location */
  323.     m = buildmark(text);
  324.  
  325.     /* move forward to the first word of the next sentence */
  326.     m = m_fword(m, 1L, 'w', '\0');
  327.     if (m == MARK_UNSET)
  328.     {
  329.         return(MARK_EOF); /*-g.t.*/
  330.     }
  331.  
  332. #ifndef CRUNCH
  333.     /* don't cross the paragraph boundary */
  334.     if (pp && ((cmd=='(') ? (m<pp) : (m>pp)))
  335.     {
  336.         m = pp;
  337.     }
  338. #endif
  339.  
  340.     return m;
  341. }
  342. #endif
  343.  
  344. MARK    m_paragraph(m, cnt, cmd)
  345.     MARK    m;    /* movement is relative to this mark */
  346.     long    cnt;    /* a numeric argument */
  347.     int    cmd;    /* either '{' or '}' */
  348. {
  349.     char    *text;    /* text of the current line */
  350.     char    *pscn;    /* used to scan thru value of "paragraphs" option */
  351.     long    l, ol;    /* current line number, original line number */
  352.     int    dir;    /* -1 if we're moving up, or 1 if down */
  353.     char    col0;    /* character to expect in column 0 */
  354.     long    limit;    /* line where searching must stop */
  355. #ifndef NO_SENTENCE
  356. # define SENTENCE(x)    (x)
  357.     char    *list;    /* either o_sections or o_paragraph */
  358. #else
  359. # define SENTENCE(x)
  360. #endif
  361. #ifndef CRUNCH
  362.     MARK    ss;
  363. #endif
  364.  
  365.     DEFAULT(1);
  366.  
  367.     /* set the direction, based on the command */
  368.     switch (cmd)
  369.     {
  370.       case '{':
  371.         dir = -1;
  372.         col0 = '\0';
  373.         SENTENCE(list = o_paragraphs); 
  374. #ifndef CRUNCH
  375.         ss = m_paragraph(m, 1L, '<');
  376.         if (ss)
  377.             limit = markline(ss);
  378.         else
  379. #endif
  380.             limit = 1L;
  381.         break;
  382.  
  383.       case '}':
  384.         dir = 1;
  385.         col0 = '\0';
  386.         SENTENCE(list = o_paragraphs); 
  387. #ifndef CRUNCH
  388.         ss = m_paragraph(m, 1L, '>');
  389.         if (ss)
  390.             limit = markline(ss);
  391.         else
  392. #endif
  393.             limit = nlines;
  394.         break;
  395.  
  396.       case '[':
  397.         col0 = getkey(0);
  398.         if (col0 != '[')
  399.         {
  400. #ifndef NO_LEARN
  401.             /* if 'a through 'z, then setup learn mode */
  402.             if (col0 >= 'a' && col0 <= 'z')
  403.             {
  404.                 if (col0 == learn)
  405.                 {
  406.                     learn = '\0';
  407.                     learnkey('\0');
  408.                 }
  409.                 learn = col0;
  410.                 return cursor;
  411.             }
  412. #endif
  413.             return MARK_UNSET;
  414.         }
  415.         /* fall through... */
  416.       case '<':
  417.         dir = -1;
  418.         col0 = '{';
  419.         SENTENCE(list = o_sections); 
  420.         limit = 1L;
  421.         break;
  422.  
  423.       case ']':
  424.         col0 = getkey(0);
  425.         if (col0 != ']')
  426.         {
  427. #ifndef NO_LEARN
  428.             /* if 'a through 'z, then end learn mode */
  429.             if (col0 >= 'a' && col0 <= 'z')
  430.             {
  431.                 if (col0 != learn)
  432.                 {
  433.                     beep();
  434.                 }
  435.                 learn = '\0';
  436.                 return cursor;
  437.             }
  438. #endif
  439.             return MARK_UNSET;
  440.         }
  441.         /* fall through... */
  442.       case '>':
  443.         dir = 1;
  444.         col0 = '{';
  445.         SENTENCE(list = o_sections); 
  446.         limit = nlines;
  447.         break;
  448.     }
  449.     ol = l = markline(m);
  450.  
  451.     /* for each paragraph that we want to travel through... */
  452.     while (l != limit && cnt-- > 0)
  453.     {
  454.         /* skip blank lines between paragraphs *